package start

import (
	"context"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"vblog/conf"
	"vblog/ioc"
	"vblog/logger"
	"vblog/protocol"

	_ "vblog/apps"

	"github.com/gin-gonic/gin"
	libioc "github.com/infraboard/mcube/ioc"
	"github.com/spf13/cobra"
)

var (
	configType string
	configFile string
)

// vblog-api start
var Cmd = &cobra.Command{
	Use:   "start",
	Short: "vblog项目后端",
	Long:  ``,
	Run: func(cmd *cobra.Command, args []string) {
		// 命令具体的执行逻辑
		// vblog-api start xxx xx xx xx
		// args就是数组[xxx xx xx xx]

		// 个程序的组装
		// 1. 加载配置
		switch configType {
		case "env":
			_, err := conf.LoadConfigFromEnv()
			cobra.CheckErr(err)
		default:
			_, err := conf.LoadConfigFromToml(configFile)
			cobra.CheckErr(err)
		}
		// 加载业务逻辑实现
		r := gin.Default()

		// blog 业务模块

		// v1.0
		// blogService := &impl.Impl{}
		// err := blogService.Init()
		// cobra.CheckErr(err)
		// apiHandler := api.NewHandler(blogService)
		// apiHandler.Registry(r)

		// v2.0所有注册到ioc里面的对象统一初始化

		// 提前打印下当前已经加载的实例
		logger.L().Debug().Msgf("controllers: %s", ioc.ShowLoadedControllers())
		logger.L().Debug().Msgf("apis: %s", ioc.ShowLoadedApis())
		err := ioc.InitController()
		cobra.CheckErr(err)
		err = ioc.InitHttpApi("/vblog/api/v1", r)
		cobra.CheckErr(err)

		// 启动Http协议服务器
		httpServer := protocol.NewHttp(r)
		go func() {

			herr := httpServer.Start()
			if herr != http.ErrServerClosed {
				cobra.CheckErr(herr)
			}
		}()
		// 启动Grpc协议服务器
		grpcserver := protocol.NewGrpc()
		go func() {
			gerr := grpcserver.Start()
			cobra.CheckErr(gerr)
		}()

		// 如果进程推出了,是没有资源释放逻辑的
		// 1. 正在处理的请求,会直接失败
		// 2. 数据库或者一些事物状态会出现异常
		// 3. 一些打开的文件 需要关闭
		// 4. 一些正在消费的队列(kafka), 停止处理
		err = libioc.InitIocObject()
		cobra.CheckErr(err)
		// 信号处理 负责阻塞住主进程(Loop Os Sign)
		ch := make(chan os.Signal, 1)
		// 如果os发出信号后,会把该信号发往ch channal
		signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGHUP, syscall.SIGQUIT)
		// 从channel 中获取信号
		s := <-ch
		logger.L().Info().Msgf("receive os signal: %s exit....", s)
		// 做后续处理
		ctx := context.Background()
		httpServer.Stop(ctx)
		grpcserver.Stop(ctx)
		// 其他资源释放逻辑
		conf.C().MySQL.Close()
	},
}

func init() {
	// Flag --config-type -t file -f etc/config.toml
	Cmd.Flags().StringVarP(&configType, "config-type", "t", "file", "程序加载配置的方式")
	Cmd.Flags().StringVarP(&configFile, "config-file", "f", "etc/config.toml", "配置文件的路径")
}
